#include "nationalinstruments.h"

#define DAQmxErrChk(functionCall) if( DAQmxFailed(error=(functionCall)) ) goto Error; else

NationalInstruments::NationalInstruments(QObject * parent)//: QObject( parent)
{
    parent;
    //QDebug(QtDebugMsg) << "Released keyboard." << endl;
    //qDebug() << "Released keyboard." << endl;

    bResonantScanning = false;
    nLinesPerFrame = 512;
    nPulseDelay = 291;
    nPulseDelay1x = 291,
    nPulseDelay2x = 291,
    nPulseDelay4x = 291,
    nPulseDelay8x = 291,
    nPulseDelay16x = 291,
    nPulseDelay32x = 291,
    nPulseDelay64x = 291;
    dYScanAmplitudeVolts = 8.0;
    dYScanOffsetVolts = 0.0;
    dYScanFraction = 0.3;
    dXResonanceFrequency = 8000.0; //approx (bounds?)
    dXScanAmplitudeVolts = 5.0;
    dXScanFraction = 1.0;
    this->dYRampDutyCycle = 0.8;
    nActuatorPinoutVersion = 2;

    dFastFreq = 8.0;

    nEdgeWidth = 4;

    bFastBlank = true;
    bSlowBlank = true;
    dLaserPower = 1.0;

    dFastBlankDelay = 0.0;
    dFastBlankWidth = 1.0;
    dSlowBlankDelay = 0.0;
    dSlowBlankWidth = 1.0;
}

NationalInstruments::~NationalInstruments()
{
    Shutdown();
}

void NationalInstruments::Initialize()
{
    //use freq_out special counter if needed
    //InitializeFrequencyOutput();

    //DAQmxSetDigitalLogicFamilyPowerUpState( "Dev1", DAQmx_Val_5V );


    //turn off scanner
    bResonantScanning = false;
    SetResonantScannerSelectBits(0, 0, 0);
}



void NationalInstruments::InitializeFrequencyOutput()
{

    //This function is obsolete, may be useful for generating fixed digital frequencies
    int32       error=0;
    char        errBuff[2048]={'\0'};
    tFreqOutput = 0;

    //Start Trigger P1.1

    DAQmxErrChk (DAQmxCreateTask("",&tFreqOutput));
    DAQmxErrChk (DAQmxCreateCOPulseChanFreq(tFreqOutput, "Dev1/freqout","",DAQmx_Val_Hz , DAQmx_Val_Low , 0.0, 100000.0,0.5 ));
    DAQmxErrChk (DAQmxCfgImplicitTiming(tFreqOutput,DAQmx_Val_ContSamps,1000));
    DAQmxErrChk (DAQmxStartTask(tFreqOutput));

Error:
    if( DAQmxFailed(error) )
    {
        DAQmxGetExtendedErrorInfo(errBuff,2048);
        //better clear task because it was succesfully created
        if( tFreqOutput!=0 ) {
                DAQmxStopTask(tFreqOutput);
                DAQmxClearTask(tFreqOutput);
        }
    }

    return;
}


void NationalInstruments::ChangeFirgelliState(int state, int id)
{
    int32       error=0;
    TaskHandle  taskHandleA=0;
    TaskHandle  taskHandleB=0;
    uInt8       dataA[8] = {0,0,0,0,0,0,0,0};
    uInt8       dataB[8] = {1,1,1,1,1,1,1,1};
    char        errBuff[2048]={'\0'};

    //unused, for future multiple firgellis
    id;

    //A ports
    //(Portera-lab)
    //P2.7, P0.1, P0.2, P0.3
    //B ports
    //P0.4, P0.5, P1.4, P1.5

    //A ports
    //(Version B)
    //P1.2 1.4 1.6 1.7
    //B ports
    //P2.0 2.1 2.2 2.3

    QString sPinoutA, sPinoutB;
    //PINOUTS
    //1 - portera translation scope
    //3 - portera resonant scope, cafferty scope
    //2 - hofer scope, bonin scope, london scope

    if(nActuatorPinoutVersion == 2)
    {
        sPinoutA.sprintf("Dev1/port0/line2, Dev1/port0/line7");

        DAQmxErrChk (DAQmxCreateTask("",&taskHandleA));
        DAQmxErrChk (DAQmxCreateDOChan(taskHandleA,
          sPinoutA.toAscii(),"",DAQmx_Val_ChanForAllLines));

        //just debug
        uInt32 temp;
        int myint;
        myint = DAQmxGetWriteDigitalLinesBytesPerChan(taskHandleA,&temp);

        //start digital output
        DAQmxErrChk (DAQmxStartTask(taskHandleA));

        if (state==0)
        {
            DAQmxErrChk (DAQmxWriteDigitalLines(taskHandleA,1,1,10.0,DAQmx_Val_GroupByChannel,dataA,NULL,NULL));

            DAQmxStopTask(taskHandleA);
            DAQmxClearTask(taskHandleA);
        }
        else
        {
            DAQmxErrChk (DAQmxWriteDigitalLines(taskHandleA,1,1,10.0,DAQmx_Val_GroupByChannel,dataB,NULL,NULL));

            DAQmxStopTask(taskHandleA);
            DAQmxClearTask(taskHandleA);
        }

        return;
    }

    if(nActuatorPinoutVersion == 1) //Portera translation
    {
        sPinoutA.sprintf("Dev1/port2/line7, Dev1/port0/line1, Dev1/port0/line2, Dev1/port0/line3");
        sPinoutB.sprintf("Dev1/port0/line4, Dev1/port0/line5, Dev1/port1/line4, Dev1/port1/line5");
    }
    else if(nActuatorPinoutVersion == 3)  //Portera resonant, Cafferty
    {
        sPinoutA.sprintf("Dev1/port1/line2, Dev1/port1/line4, Dev1/port1/line6, Dev1/port1/line7");
        sPinoutB.sprintf("Dev1/port2/line0, Dev1/port2/line1, Dev1/port2/line2, Dev1/port2/line3");
    }
    else //external relay--only first two lines are used.
    {
    }

    //Shutter P0.6

    DAQmxErrChk (DAQmxCreateTask("",&taskHandleA));
    DAQmxErrChk (DAQmxCreateDOChan(taskHandleA,
      sPinoutA.toAscii(),"",DAQmx_Val_ChanForAllLines));

    //just debug
    uInt32 temp;
    int myint;
    myint = DAQmxGetWriteDigitalLinesBytesPerChan(taskHandleA,&temp);


    DAQmxErrChk (DAQmxCreateTask("",&taskHandleB));
    DAQmxErrChk (DAQmxCreateDOChan(taskHandleB,
      sPinoutB.toAscii(),"",DAQmx_Val_ChanForAllLines));




    //start digital output
    DAQmxErrChk (DAQmxStartTask(taskHandleA));
    DAQmxErrChk (DAQmxStartTask(taskHandleB));

    if (state==0)
    {
        DAQmxErrChk (DAQmxWriteDigitalLines(taskHandleB,1,1,10.0,DAQmx_Val_GroupByChannel,dataB,NULL,NULL));
        DAQmxErrChk (DAQmxWriteDigitalLines(taskHandleA,1,1,10.0,DAQmx_Val_GroupByChannel,dataA,NULL,NULL));
    }
    else
    {
        DAQmxErrChk (DAQmxWriteDigitalLines(taskHandleB,1,1,10.0,DAQmx_Val_GroupByChannel,dataA,NULL,NULL));
        DAQmxErrChk (DAQmxWriteDigitalLines(taskHandleA,1,1,10.0,DAQmx_Val_GroupByChannel,dataB,NULL,NULL));
    }

Error:
    if( DAQmxFailed(error) )
            DAQmxGetExtendedErrorInfo(errBuff,2048);

    printf("NI: Error on change firgelli state");
    //better clear task because it was succesfully created
    if( taskHandleA!=0 ) {
            DAQmxStopTask(taskHandleA);
            DAQmxClearTask(taskHandleA);
            DAQmxStopTask(taskHandleB);
            DAQmxClearTask(taskHandleB);
    }

    return;

}



void NationalInstruments::SetDigitalLine(const char* cDevicePortLine, uInt8 state)
{

    //sets a single digital line.  see pulse fuction for a square trigger pulse

    int32       error=0;
    TaskHandle  taskHandleA=0;
    uInt8       dataA[1] = {1};
    char        errBuff[2048]={'\0'};

    //Start Trigger P1.1
    //doing so on P2.5?

    dataA[0] = state;


    DAQmxErrChk (DAQmxCreateTask("",&taskHandleA));

    DAQmxErrChk (DAQmxCreateDOChan(taskHandleA, cDevicePortLine,"",DAQmx_Val_ChanPerLine));
    //DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandleA,"/Dev1/FrequencyOutput",100000,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps, 0));
    DAQmxErrChk (DAQmxStartTask(taskHandleA));

    //notice for Port > 0, sample clock and digital waveforms are not allowed.  so purely by software we flip the trigger
    DAQmxErrChk (DAQmxWriteDigitalLines(taskHandleA,1,true,10.0,DAQmx_Val_GroupByChannel,dataA,NULL,NULL));

    DAQmxStopTask(taskHandleA);
    DAQmxClearTask(taskHandleA);



Error:
    if( DAQmxFailed(error) )
    {
        printf("NI: Error on set digital line");
            DAQmxGetExtendedErrorInfo(errBuff,2048);

        //better clear task because it was succesfully created
        if( taskHandleA!=0 ) {
                DAQmxStopTask(taskHandleA);
                DAQmxClearTask(taskHandleA);
        }
    }


    return;
}


void NationalInstruments::OpenShutter(int id)
{
    //multiple shutters in future
    id;

    //set corresponding lines
    SetDigitalLine("Dev1/port0/line1",1);

    return;
}

void NationalInstruments::CloseShutter(int id)
{
    id;
    SetDigitalLine("Dev1/port0/line1",0);
    return;
}




void NationalInstruments::OutputDigitalPulse(const char* cDevicePortLine, int state)
{

    //writes a digital pulse to a line, generally for start trigger for ScanImage system

    int32       error=0;
    TaskHandle  taskHandleA=0;
    uInt8       dataA[1] = {1};
    uInt8       dataB[1] = {0};
    char        errBuff[2048]={'\0'};

    //Start Trigger P1.1
    //doing so on P2.5?

    //future inversion
    state;

    //CHECK FOR CAFFERTY SYSTEM
    cDevicePortLine;


    DAQmxErrChk (DAQmxCreateTask("",&taskHandleA));
    DAQmxErrChk (DAQmxCreateDOChan(taskHandleA, "Dev1/port2/line5","",DAQmx_Val_ChanForAllLines));
    //DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandleA,"/Dev1/FrequencyOutput",100000,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps, 0));
    DAQmxErrChk (DAQmxStartTask(taskHandleA));

    //notice for Port > 0, sample clock and digital waveforms are not allowed.  so purely by software we flip the trigger
    DAQmxErrChk (DAQmxWriteDigitalLines(taskHandleA,1,true,10.0,DAQmx_Val_GroupByChannel,dataA,NULL,NULL));
    DAQmxErrChk (DAQmxWriteDigitalLines(taskHandleA,1,true,10.0,DAQmx_Val_GroupByChannel,dataB,NULL,NULL));

    DAQmxStopTask(taskHandleA);
    DAQmxClearTask(taskHandleA);



Error:
    if( DAQmxFailed(error) )
    {
        printf("NI: Error on output pulse");
            DAQmxGetExtendedErrorInfo(errBuff,2048);

        //better clear task because it was succesfully created
        if( taskHandleA!=0 ) {
                DAQmxStopTask(taskHandleA);
                DAQmxClearTask(taskHandleA);
        }
    }


    return;
}



void NationalInstruments::SetResonantScannerSelectBits(int sel1, int sel2, int shutoff)
{


    //DC single point setting for SEL1, SEL2, and Relay Shutoff
    tCRSDigital     =   0;

    //TODO, separate task start and shutdown
    //figure out which lines in DataA correspond to SEL1, SEL2

    int32       error=0;
    //returned 4 bytes per channel
    uInt8       dataA[8] = {0,0,0,0,0,0,0,0};
    char        errBuff[2048]={'\0'};

    //see DAQmx help on digital data byte ordering
    //generally LSB first, and for individual lines, unused data is still present but zeroed

    //if(sel1) dataA[0] |=    0x10;
    //if(sel2) dataA[0] |=    0x20;
    //if(shutoff) dataA[0] |= 0x40;

    if(sel1) dataA[4] = 1;
    if(sel2) dataA[5] = 1;
    if(shutoff) dataA[6] = 1;
    if(shutoff) dataA[2] = 1;

    DAQmxErrChk (DAQmxCreateTask("",&tCRSDigital));
    DAQmxErrChk (DAQmxCreateDOChan(tCRSDigital,
      "Dev1/port0/line4, Dev1/port0/line5, Dev1/port0/line6","",DAQmx_Val_ChanForAllLines));

    //debug, check bytes per line
    uInt32 temp;
    int myint;
    myint = DAQmxGetWriteDigitalLinesBytesPerChan(tCRSDigital,&temp);

    DAQmxErrChk (DAQmxStartTask(tCRSDigital));

    DAQmxErrChk (DAQmxWriteDigitalLines(tCRSDigital,1,1,10.0,DAQmx_Val_GroupByChannel,dataA,NULL,NULL));

    DAQmxErrChk (DAQmxStopTask(tCRSDigital));
    DAQmxErrChk (DAQmxClearTask(tCRSDigital));
    tCRSDigital = 0;

Error:
    if( DAQmxFailed(error) )
    {
        printf("NI: Error on set res bits");
            DAQmxGetExtendedErrorInfo(errBuff,2048);
    }

}


void NationalInstruments::SetResonantScannerAmplitude(double scanfraction)
{


    int32       error           =   0;
    char        errBuff[2048]={'\0'};
    int32         nWritten = 0;

    //DC Single point setting for scan amplitude
    TaskHandle  tCRSAmplitude   =   0;
    float64     CRSData[1];

    memset(CRSData, 0, sizeof(float64));

    //TAKE SCANFRACTION AND MULTIPLY BY MAXIMUM ALLOWED VOLTAGE
    CRSData[0] = this->dXScanAmplitudeVolts * scanfraction;



    DAQmxErrChk(DAQmxCreateTask( "",&tCRSAmplitude ));
    DAQmxErrChk(DAQmxCreateAOVoltageChan( tCRSAmplitude, "Dev1/ao1", "", 0, 5.0, DAQmx_Val_Volts, "" ));
    DAQmxErrChk(DAQmxStartTask( tCRSAmplitude ));
    DAQmxErrChk(DAQmxWriteAnalogF64( tCRSAmplitude, 1, false, 1.0, DAQmx_Val_GroupByChannel, CRSData, &nWritten, NULL ));
    DAQmxStopTask( tCRSAmplitude );
    DAQmxClearTask( tCRSAmplitude );


    //doesn't work in this scope
    QDebug(QtDebugMsg) << "National Instruments: Set resonant amplitude voltage " << double(CRSData[0])
                       << " dXScanAmplitudeVolts " << dXScanAmplitudeVolts
                       << " scanfraction " << scanfraction
                       << endl;

    return;

    Error:
        if( DAQmxFailed(error) )
        {
            printf("NI: Error on set amplitude\n");
                DAQmxGetExtendedErrorInfo(errBuff,2048);
                if(tCRSAmplitude)
                {
                    DAQmxStopTask(tCRSAmplitude);
                    DAQmxClearTask(tCRSAmplitude);
                }
        }
}


void NationalInstruments::SetResonantScannerStandby(bool standby)
{

    //unused function for now
    standby;

}


void NationalInstruments::StartResonantScanning()
{

    if(bResonantScanning)
    {
        printf("NI Start Res: Already resonant scanning, stop first\n");
        return;
    }

    int32       error           =   0;
    char        errBuff[2048]={'\0'};


    //Analog output, 10MHz clocked. Identical in timing to CLYCommand.
    TaskHandle  tPockelsCell    =   0;


    //use digital lines?
    TaskHandle  tMicroscopeDigital  =   0;
    tMicroscopeDigital;

    tCRSSyncCounter =   0;

    int delay = nPulseDelay;

    DAQmxErrChk (DAQmxCreateTask("",&tCRSSyncCounter));
    DAQmxErrChk (DAQmxCreateCOPulseChanTicks(  tCRSSyncCounter, "Dev1/ctr1","","20MHzTimebase", DAQmx_Val_Low , delay, 1000, 1000 ));
    DAQmxErrChk (DAQmxCfgDigEdgeStartTrig(tCRSSyncCounter, "PFI5", DAQmx_Val_Rising ));
    DAQmxErrChk (DAQmxSetStartTrigRetriggerable(tCRSSyncCounter, true));

    //divider, from CRSSyncCounter Routed to CLYCommand (X-series STC3 retriggerable) start trigger.
    //in the case of M-series, trigger is routed to function generator.
    //also, this trigger is VSync, sent to Matrox
    tVSyncDivider =   0;
    double dResonantFrequency = dXResonanceFrequency;
    //Temporary hardcoding of resonant scanning frequency.
    //Remove to specify resonant scanning frequency in ini file
    //dResonantFrequency = 8000.0;

    //Resonant cycles per frame is half of the lines per frame
    //Lines per frame is determined by user input in the UI
    int     nResonantCyclesPerFrame = nLinesPerFrame/2;
    DAQmxErrChk (DAQmxCreateTask("",&tVSyncDivider));
    DAQmxErrChk (DAQmxCreateCOPulseChanTicks( tVSyncDivider, "Dev1/ctr0", "", "Ctr1InternalOutput", DAQmx_Val_Low , NULL, nResonantCyclesPerFrame-10, 10 ));
    DAQmxErrChk (DAQmxCfgImplicitTiming(tVSyncDivider, DAQmx_Val_ContSamps, NULL));

    //Analog output, 10MHz clocked retriggerable started ramp or sawtooth (BIDI)
    //Sample clock timing frequency is not used i suppose

    //Should work for reasonable ranges--future, parameterize
    //and parameterize max ranges

    tNI_AnalogOut     =   0;
    float64     *NI_AnalogOutData = 0;
    int n_NISize = 500000;
    NI_AnalogOutData = new float64[n_NISize];
    memset(NI_AnalogOutData, 0, sizeof(float64)*n_NISize);
    int32         nCLYWritten = 0;
    tPockelsCell     =   0;
    //int32         nPockelsWritten = 0;

    //specify slow axis DAC frequency
    double dFrameSampleClockFrequency     =    dResonantFrequency*2;
    int nSamplesPerLine = 30;
    double dPockelsMaxVoltage = 2.0;

    //specify slow axis duty cycle/flyback duration, hardcoded for now
    //double dFrameSampleClockDutyCycle         =     dYRampDutyCycle;
    //double dFlybackDutyCycle = 1.0 - dFrameSampleClockDutyCycle;

    //total number of ao samples, at resonant clock * supersampling factor for pockels cell precision
    int nPockelsCellSamples = nLinesPerFrame * nSamplesPerLine;

    //ao samples are arranged in one buffer, in series, for both channels.  second half of buffer is ao2
    int nStartOfPockelsCellSamples = nPockelsCellSamples;

    //calculate which AO samples are frame, and which are flyback
    int nFrameSamples = int(nPockelsCellSamples*dYRampDutyCycle);
    int nFlybackSamples = nPockelsCellSamples - nFrameSamples;

    //calculate fractional samples per line, based on corrected resonant frequency
    //dEdgeStride is the actual freq
    double dFractionalSamplesPerLine = dResonantFrequency/(dFastFreq*1000) * nSamplesPerLine;

    //generate a simple ramp
    for(int i = 0; i < nFrameSamples; i++)
    {
        NI_AnalogOutData[i] = dYScanFraction * dYScanAmplitudeVolts * (double(i)/double(nFrameSamples) - 0.5 + dYScanOffsetVolts);
    }

    //generate flyback reverse ramp
    for(int i = 0; i < nFlybackSamples; i++)
    {
        NI_AnalogOutData[nFrameSamples + i] = dYScanFraction * dYScanAmplitudeVolts * (1.0 - double(i)/double(nFlybackSamples) - 0.5 + dYScanOffsetVolts);
    }

    //generate a pockels cell blanking signal
    for(int i = 0; i < nPockelsCellSamples; i++)
    {
        //set values to normal power
        NI_AnalogOutData[nStartOfPockelsCellSamples+i] = dLaserPower*dPockelsMaxVoltage;
    }

    for(int i = 0; i < nLinesPerFrame; i++)
    {

        //this is a scanning line.  blank if at edges of scan.
        if(bFastBlank)
        {
            int delay = int(dFractionalSamplesPerLine*dFastBlankDelay);

            //using digital manual matching of resonant frequency
            //fractional samples per line is number of samples
            int nSamplesThisLine = ceil(i*dFractionalSamplesPerLine);

            int data_index = nSamplesThisLine+delay;

            //make sure we don't go beyond the ni ao data buffer limit
            if(data_index > nStartOfPockelsCellSamples) data_index = nStartOfPockelsCellSamples;
            if(data_index < 0) data_index = 0;


            //blank first and last samples of this scan line
            //for(int n = 0; n < nEdgeWidth; n++)
            //{
            //    NI_AnalogOutData[nStartOfPockelsCellSamples+nSamplesThisLine+n] = 0.0;
            //}

            NI_AnalogOutData[nStartOfPockelsCellSamples+data_index] = 0.0;

            if(i > 0)
            {
                NI_AnalogOutData[nStartOfPockelsCellSamples+data_index-1] = 0.0;
            }

        }

        if(bSlowBlank)
        {
            //width of slow blank in terms of lines
            int startwidth = nLinesPerFrame * (1.0-dYRampDutyCycle);
            int endwidth = startwidth*dSlowBlankWidth;

            //delay of slow blank in terms of lines
            int delay = nLinesPerFrame*dSlowBlankDelay;

            //blank lines a-b and c-d
            int a = 0;
            int b = 0;
            int c = nLinesPerFrame - endwidth;
            int d = nLinesPerFrame;

            //account for delay
            if (delay < 0)
            {
                c -= abs(delay);
                d -= abs(delay);
            }
            else
            {
                c += delay;
                b += delay;
                a = b - endwidth;
                if (a < 0) a = 0;

            }

            if( (i >= a && i < b ) || (i >= c && i < d) )
            {
                //this is a flyback line, so blank entire line
                for(int j = 0; j < nSamplesPerLine; j++)
                {
                    NI_AnalogOutData[nStartOfPockelsCellSamples+i*nSamplesPerLine + j] = 0.0;
                }
            }

        }
    }


    //may take permanent one time adjustment "line length" in clock cycles
    //int nLineLengthClockTicks;


    if(1)
    {

    QDebug(QtDebugMsg) << "National Instruments: Attempt resonant scanning - \n"
                       << "nFrameSamples:" << nFrameSamples << " "
                       << "dResonantFrequency:" << dResonantFrequency << " "
                       << "nResonantCyclesPerFrame:" << nResonantCyclesPerFrame << " "
                       << "nLinesPerFrame:" << nLinesPerFrame << " "
                       << "dYScanFraction:" << dYScanFraction << " "
                       << "YVoltage:" << dYScanFraction * dYScanAmplitudeVolts << " "
                       << "XVoltage:" << dXScanFraction * dXScanAmplitudeVolts << " "
                       << "dXResonanceFrequency:"    << dXResonanceFrequency;

    DAQmxErrChk (DAQmxCreateTask( "",&tNI_AnalogOut));
    DAQmxErrChk (DAQmxCreateAOVoltageChan( tNI_AnalogOut, "Dev1/ao0,Dev1/ao2", "", -4.0, 4.0, DAQmx_Val_Volts, ""));
    DAQmxErrChk (DAQmxCfgSampClkTiming( tNI_AnalogOut, NULL, dFrameSampleClockFrequency * nSamplesPerLine, DAQmx_Val_Rising , DAQmx_Val_FiniteSamps , nPockelsCellSamples  ));
    //Retriggerable on X series
    DAQmxErrChk (DAQmxCfgDigEdgeStartTrig( tNI_AnalogOut, "Ctr0InternalOutput", DAQmx_Val_Rising ));
    DAQmxErrChk (DAQmxSetStartTrigRetriggerable( tNI_AnalogOut, true));
    DAQmxErrChk (DAQmxSetWriteRegenMode( tNI_AnalogOut, DAQmx_Val_AllowRegen ));
    DAQmxErrChk (DAQmxWriteAnalogF64(tNI_AnalogOut, nPockelsCellSamples, false, 1.0, DAQmx_Val_GroupByChannel, NI_AnalogOutData, &nCLYWritten, NULL));

}

    /*
    if(0)
    {
    DAQmxErrChk (DAQmxCreateTask( "",&tPockelsCell));
    DAQmxErrChk (DAQmxCreateAOVoltageChan( tPockelsCell, "Dev1/ao2", "", -4.0, 4.0, DAQmx_Val_Volts, ""));
    DAQmxErrChk (DAQmxCfgSampClkTiming( tPockelsCell, "", dFrameSampleClockFrequency * nSamplesPerLine, DAQmx_Val_Rising , DAQmx_Val_FiniteSamps , nPockelsCellSamples  ));
    //Retriggerable on X series
    DAQmxErrChk (DAQmxCfgDigEdgeStartTrig( tPockelsCell, "Ctr0InternalOutput", DAQmx_Val_Rising ));
    DAQmxErrChk (DAQmxSetStartTrigRetriggerable( tPockelsCell, true));
    DAQmxErrChk (DAQmxSetWriteRegenMode( tPockelsCell, DAQmx_Val_AllowRegen ));
    DAQmxErrChk (DAQmxWriteAnalogF64(tPockelsCell, nPockelsCellSamples, false, 1.0, DAQmx_Val_GroupByChannel, PockelsData, &nPockelsWritten, NULL));
}

*/




    //start all tasks in reverse dependance order

    //set resonant amplitude
    SetResonantScannerAmplitude(dXScanFraction);


    //DAQmxErrChk  (DAQmxStartTask(tPockelsCell));
    DAQmxErrChk  (DAQmxStartTask(tNI_AnalogOut));
    //DAQmxErrChk  (DAQmxStartTask(tFrameSampleClock));
    DAQmxErrChk  (DAQmxStartTask(tVSyncDivider));
    DAQmxErrChk  (DAQmxStartTask(tCRSSyncCounter));

    printf("NI: Started resonant scanning (success).\n");
    bResonantScanning = true;
    delete [] NI_AnalogOutData;
    NI_AnalogOutData = 0;



Error:

    if( DAQmxFailed(error) )
    {
        if (NI_AnalogOutData) delete [] NI_AnalogOutData;
            DAQmxGetExtendedErrorInfo(errBuff,2048);
            printf("DAQmx error on start resonant scanning.  Recommend restarting software.");
    }


}





void NationalInstruments::StopResonantScanning()
{

    //Don't do anything if we're not already scanning
    if (!bResonantScanning)
    {
        printf("NI: Not resonant scanning - unnecessary res stop\n");
        return;
    }

    int32       error           =   0;
    char        errBuff[2048]={'\0'};

    DAQmxErrChk  (DAQmxStopTask(tVSyncDivider));
    DAQmxErrChk  (DAQmxClearTask(tVSyncDivider));
    tVSyncDivider = 0;

    DAQmxErrChk  (DAQmxStopTask(tCRSSyncCounter));
    DAQmxErrChk  (DAQmxClearTask(tCRSSyncCounter));
    tCRSSyncCounter = 0;

    DAQmxErrChk  (DAQmxStopTask(tNI_AnalogOut));
    DAQmxErrChk  (DAQmxClearTask(tNI_AnalogOut));
    tNI_AnalogOut = 0;

    //DAQmxErrChk  (DAQmxStopTask(tPockelsCell));
    //DAQmxErrChk  (DAQmxClearTask(tPockelsCell));
    tPockelsCell = 0;

    printf("Stopped resonant scanning.\n");
    bResonantScanning = false;


Error:
    if( DAQmxFailed(error) )
    {
            DAQmxGetExtendedErrorInfo(errBuff,2048);
            printf("DAQmx error on stop resonant scanning.  Recommend restarting software.");
    }
}

void NationalInstruments::ResetHSync()
{
    if(!bResonantScanning)
    {
        printf("NI: Not resonant scanning, hsync reset not necessary.\n");
        return;
    }
    else
    {
        printf("NI: Reset hsync.\n");
    }

    int32       error           =   0;
    char        errBuff[2048]={'\0'};
    DAQmxErrChk  (DAQmxStopTask(tCRSSyncCounter));
    DAQmxErrChk  (DAQmxClearTask(tCRSSyncCounter));
    tCRSSyncCounter = 0;

    //note pulse width of h-sync is given by the values at end of createcopulsechanticks, in 20mhz ticks.
    tCRSSyncCounter =   0;

    int delay = nPulseDelay;

    DAQmxErrChk (DAQmxCreateTask("",&tCRSSyncCounter));
    DAQmxErrChk (DAQmxCreateCOPulseChanTicks(  tCRSSyncCounter, "Dev1/ctr1","","20MHzTimebase", DAQmx_Val_Low , delay, 1000, 1000 ));
    DAQmxErrChk (DAQmxCfgDigEdgeStartTrig(tCRSSyncCounter, "PFI5", DAQmx_Val_Rising ));

    //note that counter output samples are 8bit values specifying length of up or down states in length
    //think tiago's up and down states
    //thus for our case, the number of samples is by default simply 2
    //however, for double pulse generation with delay, this should be 4.

    //DAQmxErrChk (DAQmxCfgImplicitTiming(tCRSSyncCounter, DAQmx_Val_FiniteSamps, uInt64(20)));
    DAQmxErrChk (DAQmxSetStartTrigRetriggerable(tCRSSyncCounter, true));
    //DAQmxSetStartTrigType(tCRSSyncCounter, int32 data) (for x series, retriggerable


    DAQmxErrChk  (DAQmxStartTask(tCRSSyncCounter));

Error:
    if( DAQmxFailed(error) )
    {
            DAQmxGetExtendedErrorInfo(errBuff,2048);
            printf("DAQmx error on hsync reset.  Recommend restarting software.\n");
    }
}



//Unused for now
void NationalInstruments::ShutdownFrequencyOutput()
{


    int32       error=0;
    char        errBuff[2048]={'\0'};

    //Start Trigger P1.1


    DAQmxErrChk(DAQmxStopTask(tFreqOutput));
    DAQmxErrChk(DAQmxClearTask(tFreqOutput));

Error:
    if( DAQmxFailed(error) )
            DAQmxGetExtendedErrorInfo(errBuff,2048);

    //better clear task because it was succesfully created
    if( tFreqOutput!=0 ) {
            DAQmxStopTask(tFreqOutput);
            DAQmxClearTask(tFreqOutput);
    }
    printf("DAQmx error.  Recommend restarting software.\n");
}




void NationalInstruments::Shutdown()
{
    StopResonantScanning();

    //turn off scanner
    SetResonantScannerSelectBits(0, 0, 0);
    //ShutdownFrequencyOutput();
}
